package com.dfs.parent.common.feign.config;

import com.dfs.parent.common.feign.props.GrayProperties;
import com.dfs.parent.common.feign.rule.GrayRoundRobinLoadBalancer;
import org.springframework.beans.factory.ObjectProvider;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.loadbalancer.core.ReactorLoadBalancer;
import org.springframework.cloud.loadbalancer.core.ServiceInstanceListSupplier;
import org.springframework.cloud.loadbalancer.support.LoadBalancerClientFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.core.env.Environment;

/**
 * @Description 灰度配置类
 * 不能添加@Configuration ，直接添加@Configuration 会导致 String serviceId = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);serviceId为null
 * 因为这里的参数是feign传过来的，添加@Configuration 初始化就会加载，参赛为null会报错
 * @Author dahong
 * @Date 2024/2/22 05:56
 * 为什么不用一个header头去判断开关是否走灰度，因为gateway打开灰度后，没有给不是灰度用户添加header头，就是让其走老版本的服务。如果你用header去判断，他可能会走到新部署的版本。
 */
public class GrayLoadBalancerConfig {
    @Autowired
    private GrayProperties grayProperties;
    @Bean
    public ReactorLoadBalancer<ServiceInstance> dynamicLoadBalancer(Environment environment
            , LoadBalancerClientFactory loadBalancerClientFactory) {
        String serviceId = environment.getProperty(LoadBalancerClientFactory.PROPERTY_NAME);
        // LoadBalancerClientFactory 中懒加载（Lazy Load）某个服务（serviceId）对应的 ServiceInstanceListSupplier 实例
        //  serviceId：目标微服务的名称（如 user-service）
//        ObjectProvider<ServiceInstanceListSupplier> supplierProvider =
//                loadBalancerClientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class);
            //  开启灰度
            return new GrayRoundRobinLoadBalancer(loadBalancerClientFactory.getLazyProvider(serviceId, ServiceInstanceListSupplier.class), serviceId,grayProperties);

    }
}
/**
 * 懒加载（Lazy Load）：
 * 只有在真正需要时（如第一次请求）才会创建 ServiceInstanceListSupplier，避免启动时不必要的初始化。
 * 适用于动态场景，例如：
 * 某些服务可能没有注册到注册中心。
 * 负载均衡策略可能根据配置动态变化。
 * 灵活性：
 * ObjectProvider 允许安全地获取 Bean，即使它不存在也不会直接抛异常（可以通过 getIfAvailable() 判断）。
 * 方法	特点	适用场景
 * getLazyProvider()	返回 ObjectProvider，支持懒加载和安全获取	推荐：动态获取，避免过早初始化
 * getInstance()	直接返回实例，可能触发立即初始化	需要立即使用的场景
 * getIfAvailable()	安全获取，不存在时返回 null	需要判空的场景
 * getLazyProvider(serviceId, ServiceInstanceListSupplier.class)
 * <p>
 * 用于按需获取某个服务的 ServiceInstanceListSupplier，优化性能并提高灵活性。
 * 核心价值：
 * 延迟初始化（Lazy Load）。
 * 支持动态服务发现（如新注册的服务也能被正确加载）。
 * 常见用途：
 * 在自定义 ReactorLoadBalancer 或过滤服务实例时使用。
 */
